#include <XnccType.h>
#include <cstddef>
#include <functional>
#include <unistd.h>
#include <utility>
#include "BytesEndian.h"

using MessageCallback = std::function<void(const xncc::types::Header*, const char*, std::size_t)>;
namespace xncc {
namespace foundation {
    class BufferV2
    {
      public:
        explicit BufferV2(std::size_t size = 1 << 5) : size_(size)
        {
            buffer_ = new char[static_cast<std::size_t>(size_)];
        }

        ~BufferV2() { delete[] buffer_; }

        void set_callback(MessageCallback msg_cb) { func_ = std::move(msg_cb); }

        ssize_t read_from_socket(int sockfd)
        {
#ifdef UNIT_TEST
            ssize_t read_byes =
                BufferTestSuite::MockTcpRead(sockfd, buffer_ + readable_len_,
                                             (size_ - readable_len_));  // 最大读取剩余可以写入的数据长度

#else
            ssize_t read_byes =
                ::read(sockfd, buffer_ + readable_len_, (size_ - readable_len_));  // 最大读取剩余可以写入的数据长度
#endif

            if (read_byes <= 0) {
                return read_byes;
            }
            readable_len_ += static_cast<std::size_t>(read_byes);
            std::size_t offset = 0;
            while (true) {
                const char* data_start = buffer_ + offset;
                const auto  msg_len    = get_message_len(data_start, readable_len_ - offset);
                if (msg_len == 0) {                                                 // buffer 剩余的部分还不够一个header
                    std::copy(buffer_ + offset, buffer_ + readable_len_, buffer_);  // 移动数据到buffer开头
                    readable_len_ = readable_len_ - offset;
                    break;
                }
                // 可以取到数据的长度
                if (readable_len_ - offset >= msg_len) {  // 剩余可读的数据 够一条消息
                    func_(reinterpret_cast<const types::Header*>(data_start), data_start + sizeof(types::Header),
                          msg_len - sizeof(types::Header));
                    offset += msg_len;
                }
                else {  // 剩余部分不够一条消息 有两种情况 一种buffer 长度足够 另种就是buffer太小
                    if (msg_len <= size_) {
                        std::copy(buffer_ + offset, buffer_ + readable_len_, buffer_);
                        readable_len_ = readable_len_ - offset;
                    }
                    else {
                        size_            = get_new_size(msg_len);
                        auto* new_buffer = new char[size_];
                        std::copy(buffer_ + offset, buffer_ + readable_len_,
                                  new_buffer);  // 移动数据到新的buffer开头
                        delete[] buffer_;
                        buffer_       = new_buffer;
                        readable_len_ = readable_len_ - offset;
                    }
                    break;
                }
            }
            return read_byes;
        }

        std::size_t size() const { return size_; }

        void reset() { readable_len_ = 0; }

      private:
        std::size_t get_new_size(std::size_t msg_len) const { return (size_ * 2) >= msg_len ? (size_ * 2) : msg_len; }
        static std::size_t get_message_len(const char* buffer, size_t len)
        {
            if (len < sizeof(types::Header)) {
                return 0;
            }
            const auto* header = reinterpret_cast<const types::Header*>(buffer);
            return sizeof(types::Header) + foundation::hostToNetwork32(header->bodyLen);
        }

        char*           buffer_;
        std::size_t     size_;
        std::size_t     readable_len_ = 0;
        MessageCallback func_;
    };
}  // namespace foundation
}  // namespace xncc